/****************************************************************************
 *
 *  3DSVPRT.C
 *
 *  (C) Copyright 1997 by Autodesk, Inc.
 *
 *  This program is copyrighted by Autodesk, Inc. and is licensed to you under
 *  the following conditions.  You may not distribute or publish the source
 *  code of this program in any form.  You may incorporate this code in object
 *  form in derivative works provided such derivative works are (i.) are de-
 *  signed and intended to work solely with Autodesk, Inc. products, and (ii.)
 *  contain Autodesk's copyright notice "(C) Copyright 1995 by Autodesk, Inc."
 *
 *  AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.  AUTODESK SPE-
 *  CIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
 *  A PARTICULAR USE.  AUTODESK, INC.  DOES NOT WARRANT THAT THE OPERATION OF
 *  THE PROGRAM WILL BE UNINTERRUPTED OR ERROR FREE.
 *
 ***************************************************************************/

#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include "3DSTYPE.H"
#include "3DSERR.H"
#include "3DSFTKST.H"
#include "CHUNK3DS.H"
#include "DBASE3DS.H"
#include "3DSVPRT.H"

void InitViewport3ds(viewport3ds **vp)
{
   viewport3ds *v;

   if (vp == NULL) SET_ERROR_RETURN(ERR_INVALID_ARG);

   v = *vp;
   
   if (v == NULL)
   {
      v = malloc(sizeof(viewport3ds));
      if (v == NULL) SET_ERROR_RETURN(ERR_NO_MEM);
      *vp = v;
   }

   v->type = TopView3ds;
   v->ortho.center.x = 0.0f;
   v->ortho.center.y = v->ortho.center.z = 0.0f;
   v->ortho.zoom = 0.7395f;
   v->user.center.x = v->user.center.y = v->user.center.z = 0.0f;
   v->user.zoom = 0.7395f;
   v->user.horang = 20.0f;
   v->user.verang = 30.0f;
   v->camera.name[0] = 0;
   v->size.xpos = 0;
   v->size.ypos = 0;
   v->size.width = 1000;
   v->size.height = 1000;
   
}

void ReleaseViewport3ds(viewport3ds **vp)
{
   if (vp != NULL)
   {
      free(*vp);
      *vp = NULL;
   }
}

void GetViewportEntry3ds(chunk3ds *section, viewport3ds **vp)
{
   chunk3ds *vlay, *c;
   ViewportLayout *dvlay;
   ViewportSize *dvsize;
   ViewportData *dvdata;
   long3ds portindex = 0;
   byte3ds foundv3 = False3ds;
   viewport3ds *v;

   FindNextChunk3ds(section->children, VIEWPORT_LAYOUT, &vlay);

   if (vlay != NULL)
   {
      InitViewport3ds(vp);
      ADD_ERROR_RETURN(ERR_GET_FAIL);

      v = *vp;
   
      dvlay = ReadChunkData3ds(vlay);
      ADD_ERROR_RETURN(ERR_GET_FAIL);
      
      for (c = vlay->children; c != NULL; c = c->sibling)
      {
	 switch(c->tag)
	 {
	 case VIEWPORT_SIZE:
	    dvsize = ReadChunkData3ds(c);
	    ADD_ERROR_RETURN(ERR_GET_FAIL);
	    v->size.xpos = dvsize->xpos;
	    v->size.ypos = dvsize->ypos;
	    v->size.width = dvsize->width;
	    v->size.height = dvsize->height;
	    break;
	 case VIEWPORT_DATA_3:
	    foundv3 = True3ds;
	    if (portindex == dvlay->top)
	    {
	       dvdata = ReadChunkData3ds(c);
	       ADD_ERROR_RETURN(ERR_GET_FAIL);

	       switch(dvdata->view)
	       {
	       case 0:
		  v->type = NoView3ds;
		  break;
	       case 1:
		  v->type = TopView3ds;
		  break;
	       case 2:
		  v->type = BottomView3ds;
		  break;
	       case 3:
		  v->type = LeftView3ds;
		  break;
	       case 4:
		  v->type = RightView3ds;
		  break;
	       case 5:
		  v->type = FrontView3ds;
		  break;
	       case 6:
		  v->type = BackView3ds;
		  break;
	       case 7:
		  v->type = UserView3ds;
		  break;
	       case 0xFFFF:
		  v->type = CameraView3ds;
		  break;
	       case 18:
		  v->type = SpotlightView3ds;
		  break;
	       default:
		  v->type = NoView3ds;
	       }

	       v->ortho.zoom = v->user.zoom = dvdata->zoomfactor;
	       v->ortho.center.x = v->user.center.x = dvdata->center.x;
	       v->ortho.center.y = v->user.center.y = dvdata->center.y;
	       v->ortho.center.z = v->user.center.z = dvdata->center.z;
	       v->user.horang = dvdata->horizang;
	       v->user.verang = dvdata->vertang;
	       strcpy(v->camera.name, dvdata->camname);

	    }
	    portindex++;
	    break;
	 case VIEWPORT_DATA:
	    if (foundv3) break;
	    if (portindex == dvlay->top)
	    {
	       dvdata = ReadChunkData3ds(c);
	       ADD_ERROR_RETURN(ERR_GET_FAIL);

	       switch(dvdata->view)
	       {
	       case 0:
		  v->type = NoView3ds;
		  break;
	       case 1:
		  v->type = TopView3ds;
		  break;
	       case 2:
		  v->type = BottomView3ds;
		  break;
	       case 3:
		  v->type = LeftView3ds;
		  break;
	       case 4:
		  v->type = RightView3ds;
		  break;
	       case 5:
		  v->type = FrontView3ds;
		  break;
	       case 6:
		  v->type = BackView3ds;
		  break;
	       case 7:
		  v->type = UserView3ds;
		  break;
	       case 0xFFFF:
		  v->type = CameraView3ds;
		  break;
	       case 18:
		  v->type = SpotlightView3ds;
		  break;
	       default:
		  v->type = NoView3ds;
	       }

	       v->ortho.zoom = v->user.zoom = dvdata->zoomfactor;
	       v->ortho.center.x = v->user.center.x = dvdata->center.x;
	       v->ortho.center.y = v->user.center.y = dvdata->center.y;
	       v->ortho.center.z = v->user.center.z = dvdata->center.z;
	       v->user.horang = dvdata->horizang;
	       v->user.verang = dvdata->vertang;
	       strcpy(v->camera.name, dvdata->camname);

	    }
	    portindex++;
	    break;
	 }
      }
   } else
	{
		/* Not Viewport Layout in file */
		*vp = NULL;
	}
}

/* Searches an MDATA chunk looking for a DEFAULT_VIEW chunk. *vp should allready be
   initialized before passing it to this function */
void GetDefaultView3ds(chunk3ds *section, viewport3ds *vp)
{
   chunk3ds *defv;
   chunk3ds *vtype = NULL;

   myassert(vp != NULL, "GetDefaultView3ds: arg *vp is NULL");
   
   if (section->tag == MDATA)
   {
      FindNextChunk3ds(section->children, DEFAULT_VIEW, &defv);

      if (defv != NULL) vtype = defv->children;

      if (vtype != NULL)
      {
	 switch(vtype->tag)
	 {
	 case VIEW_TOP:
	    {
	       ViewStandard *d;
	       d = ReadChunkData3ds(vtype);
	       vp->type = TopView3ds;
	       vp->ortho.center.x = d->viewtargetcoord.x;
	       vp->ortho.center.y = d->viewtargetcoord.y;
	       vp->ortho.center.z = d->viewtargetcoord.z;
	       vp->ortho.zoom = d->viewwidth / (float3ds)vp->size.width;
	       break;
	    }
	 case VIEW_BOTTOM:
	    {
	       ViewStandard *d;
	       d = ReadChunkData3ds(vtype);
	       vp->type = TopView3ds;
	       vp->ortho.center.x = d->viewtargetcoord.x;
	       vp->ortho.center.y = d->viewtargetcoord.y;
	       vp->ortho.center.z = d->viewtargetcoord.z;
	       vp->ortho.zoom = d->viewwidth / (float3ds)vp->size.width;
	       break;
	    }
	 case VIEW_LEFT:
	    {
	       ViewStandard *d;
	       d = ReadChunkData3ds(vtype);
	       vp->type = TopView3ds;
	       vp->ortho.center.x = d->viewtargetcoord.x;
	       vp->ortho.center.y = d->viewtargetcoord.y;
	       vp->ortho.center.z = d->viewtargetcoord.z;
	       vp->ortho.zoom = d->viewwidth / (float3ds)vp->size.width;
	       break;

	    }
	 case VIEW_RIGHT:
	    {
	       ViewStandard *d;
	       d = ReadChunkData3ds(vtype);
	       vp->type = TopView3ds;
	       vp->ortho.center.x = d->viewtargetcoord.x;
	       vp->ortho.center.y = d->viewtargetcoord.y;
	       vp->ortho.center.z = d->viewtargetcoord.z;
	       vp->ortho.zoom = d->viewwidth / (float3ds)vp->size.width;
	       break;

	    }
	 case VIEW_FRONT:
	    {
	       ViewStandard *d;
	       d = ReadChunkData3ds(vtype);
	       vp->type = TopView3ds;
	       vp->ortho.center.x = d->viewtargetcoord.x;
	       vp->ortho.center.y = d->viewtargetcoord.y;
	       vp->ortho.center.z = d->viewtargetcoord.z;
	       vp->ortho.zoom = d->viewwidth / (float3ds)vp->size.width;
	       break;
	 
	    }
	 case VIEW_BACK:
	    {
	       ViewStandard *d;
	       d = ReadChunkData3ds(vtype);
	       vp->type = TopView3ds;
	       vp->ortho.center.x = d->viewtargetcoord.x;
	       vp->ortho.center.y = d->viewtargetcoord.y;
	       vp->ortho.center.z = d->viewtargetcoord.z;
	       vp->ortho.zoom = d->viewwidth / (float3ds)vp->size.width;
	       break;
	 
	    }
	 case VIEW_USER:
	    {
	       ViewUser *d;
	       d = ReadChunkData3ds(vtype);
	       vp->type = UserView3ds;
	       vp->user.center.x = d->viewtargetcoord.x;
	       vp->user.center.y = d->viewtargetcoord.y;
	       vp->user.center.z = d->viewtargetcoord.z;
	       vp->user.zoom = d->viewwidth / (float3ds)vp->size.width;
	       vp->user.horang = d->xyviewangle;
	       vp->user.verang = d->yzviewangle;
	       break;
	       
	    }
	 case VIEW_CAMERA:
	    {
	       ViewCamera *d;
	       d = ReadChunkData3ds(vtype);
	       vp->type = CameraView3ds;
	       strcpy(vp->camera.name, d->name);
	       break;
	       
	    }
	 }

      }
   }
}

void PutDefaultView3ds(chunk3ds *section, viewport3ds *vp)
{
   chunk3ds *defv, *vtype;

   myassert(vp != NULL, "GetDefaultView3ds: arg *vp is NULL");
   
   if (section->tag == MDATA)
   {
      ReplaceOrAddChild3ds(section, DEFAULT_VIEW, &defv);
      ON_ERROR_RETURN;

      switch(vp->type)
      {
      case TopView3ds:
	 {
	    ViewStandard *d;
	    d = InitChunkAndData3ds(&vtype, VIEW_TOP);
	    d->viewtargetcoord.x = vp->ortho.center.x;
	    d->viewtargetcoord.y = vp->ortho.center.y;
	    d->viewtargetcoord.z = vp->ortho.center.z;
	    d->viewwidth = (float3ds)vp->size.width / vp->ortho.zoom;
	    AddChildOrdered3ds(defv, vtype);
	    break;
	 }
      case BottomView3ds:
	 {
	    ViewStandard *d;
	    d = InitChunkAndData3ds(&vtype, VIEW_BOTTOM);
	    d->viewtargetcoord.x = vp->ortho.center.x;
	    d->viewtargetcoord.y = vp->ortho.center.y;
	    d->viewtargetcoord.z = vp->ortho.center.z;
	    d->viewwidth = (float3ds)vp->size.width / vp->ortho.zoom;
	    AddChildOrdered3ds(defv, vtype);
	    break;
	 }
      case LeftView3ds:
	 {
	    ViewStandard *d;
	    d = InitChunkAndData3ds(&vtype, VIEW_LEFT);
	    d->viewtargetcoord.x = vp->ortho.center.x;
	    d->viewtargetcoord.y = vp->ortho.center.y;
	    d->viewtargetcoord.z = vp->ortho.center.z;
	    d->viewwidth = (float3ds)vp->size.width / vp->ortho.zoom;
	    AddChildOrdered3ds(defv, vtype);
	    break;
	 }
      case RightView3ds:
	 {
	    ViewStandard *d;
	    d = InitChunkAndData3ds(&vtype, VIEW_RIGHT);
	    d->viewtargetcoord.x = vp->ortho.center.x;
	    d->viewtargetcoord.y = vp->ortho.center.y;
	    d->viewtargetcoord.z = vp->ortho.center.z;
	    d->viewwidth = (float3ds)vp->size.width / vp->ortho.zoom;
	    AddChildOrdered3ds(defv, vtype);
	    break;
	 }
      case FrontView3ds:
	 {
	    ViewStandard *d;
	    d = InitChunkAndData3ds(&vtype, VIEW_FRONT);
	    d->viewtargetcoord.x = vp->ortho.center.x;
	    d->viewtargetcoord.y = vp->ortho.center.y;
	    d->viewtargetcoord.z = vp->ortho.center.z;
	    d->viewwidth = (float3ds)vp->size.width / vp->ortho.zoom;
	    AddChildOrdered3ds(defv, vtype);
	    break;
	 }
      case BackView3ds:
	 {
	    ViewStandard *d;
	    d = InitChunkAndData3ds(&vtype, VIEW_BOTTOM);
	    d->viewtargetcoord.x = vp->ortho.center.x;
	    d->viewtargetcoord.y = vp->ortho.center.y;
	    d->viewtargetcoord.z = vp->ortho.center.z;
	    d->viewwidth = (float3ds)vp->size.width / vp->ortho.zoom;
	    AddChildOrdered3ds(defv, vtype);
	    break;
	 }
      case UserView3ds:
	 {
	    ViewUser *d;
	    d = InitChunkAndData3ds(&vtype, VIEW_USER);
	    d->viewtargetcoord.x = vp->user.center.x;
	    d->viewtargetcoord.y = vp->user.center.y;
	    d->viewtargetcoord.z = vp->user.center.z;
	    d->viewwidth = (float3ds)vp->size.width / vp->user.zoom;
	    d->xyviewangle = vp->user.horang;
	    d->yzviewangle = vp->user.verang;
	    AddChildOrdered3ds(defv, vtype);
	    break;
	 }
      case CameraView3ds:
	 {
	    ViewCamera *d;
	    d = InitChunkAndData3ds(&vtype, VIEW_CAMERA);
	    d->name = strdup(vp->camera.name);
	    AddChildOrdered3ds(defv, vtype);
	    break;
	 }
      }
   }
}

void PutViewportEntry3ds(chunk3ds *section, viewport3ds *vp)
{
   chunk3ds *vlay, *vsize, *vdata, *c;
   ViewportLayout *dvlay;
   ViewportSize *dvsize;
   ViewportData *dvdata;
   ulong3ds i;
   
   /* Delete any existing viewport layout chunks */
   FindNextChunk3ds(section->children, VIEWPORT_LAYOUT, &vlay);
   if (vlay != NULL)
   {
      DeleteChunk3ds(vlay);
      /* Retag it so it can be used again */
      vlay->tag = VIEWPORT_LAYOUT;
   } else
   {
      InitChunkAs3ds(&vlay, VIEWPORT_LAYOUT);
      ON_ERROR_RETURN;
      AddChildOrdered3ds(section, vlay);
      ON_ERROR_RETURN;
   }

   dvlay = InitChunkData3ds(vlay);
   ON_ERROR_RETURN;

   /* init view to a single view configuration */
   dvlay->form = 0;
   dvlay->top = 0;
   dvlay->ready = 1;
   dvlay->wstate = 0;
   dvlay->swapws = 0;
   dvlay->swapport = 0;
   dvlay->swapcur = 0;

   dvsize = InitChunkAndData3ds(&vsize, VIEWPORT_SIZE);
   dvsize->xpos = vp->size.xpos;
   dvsize->ypos = vp->size.ypos;
   dvsize->width = vp->size.width;
   dvsize->height = vp->size.height;

   AddChildOrdered3ds(vlay, vsize);

   dvdata = InitChunkAndData3ds(&vdata, VIEWPORT_DATA_3);
   
   dvdata->flags = 1;
   dvdata->axislockout = 0;
   dvdata->winxpos = vp->size.xpos;
   dvdata->winypos = vp->size.ypos;
   dvdata->winwidth = vp->size.width;
   dvdata->winheight = vp->size.height;

   switch (vp->type)
   {
   case TopView3ds:
      dvdata->view = 1;
      break;
   case BottomView3ds:
      dvdata->view = 2;
      break;
   case LeftView3ds:
      dvdata->view = 3;
      break;
   case RightView3ds:
      dvdata->view = 4;
      break;
   case FrontView3ds:
      dvdata->view = 5;
      break;
   case BackView3ds:
      dvdata->view = 6;
      break;
   case UserView3ds:
      dvdata->view = 7;
      break;
   case CameraView3ds:
      dvdata->view = 0xFFFF;
      break;
   case SpotlightView3ds:
      dvdata->view = 18;
      break;
   }

   switch(vp->type)
   {
   case TopView3ds:
   case BottomView3ds:
   case LeftView3ds:
   case RightView3ds:
   case FrontView3ds:
   case BackView3ds:
      dvdata->zoomfactor = vp->ortho.zoom;
      dvdata->center.x = vp->ortho.center.x;
      dvdata->center.y = vp->ortho.center.y;
      dvdata->center.z = vp->ortho.center.z;
      dvdata->horizang = 20.0f;
      dvdata->vertang = 30.0f;
      dvdata->camname = strdup("");
      break;
   case UserView3ds:
      dvdata->zoomfactor = vp->user.zoom;
      dvdata->center.x = vp->user.center.x;
      dvdata->center.y = vp->user.center.y;
      dvdata->center.z = vp->user.center.z;
      dvdata->horizang = vp->user.horang;
      dvdata->vertang = vp->user.verang;
      dvdata->camname = strdup("");
      break;
   case CameraView3ds:
      dvdata->zoomfactor = 0.0f;
      dvdata->center.x = 0.0f;
      dvdata->center.y = 0.0f;
      dvdata->center.z = 0.0f;
      dvdata->horizang = 20.0f;
      dvdata->vertang = 30.0f;
      dvdata->camname = strdup(vp->camera.name);
      break;
   }

   /* Duplicate the same port 5 times */
   for (i = 0; i < 5; i++)
   {
      CopyChunk3ds(vdata, &c);
      ON_ERROR_RETURN;

      AddChildOrdered3ds(vlay, c);
      ON_ERROR_RETURN;
   }

   /* Change to the old style port */
   vdata->tag = VIEWPORT_DATA;
   for (i = 0; i < 5; i++)
   {
      CopyChunk3ds(vdata, &c);
      ON_ERROR_RETURN;

      AddChildOrdered3ds(vlay, c);
      ON_ERROR_RETURN;
   }

   ReleaseChunk3ds(&vdata);
   ON_ERROR_RETURN;

}

void GetViewport3ds(database3ds *db, viewport3ds **vp)
{
   chunk3ds *kfdata;

   if ((db == NULL) || (vp == NULL)) SET_ERROR_RETURN(ERR_INVALID_ARG);
   if (db->topchunk == NULL) SET_ERROR_RETURN(ERR_INVALID_DATABASE);
   if ((db->topchunk->tag != M3DMAGIC) && (db->topchunk->tag != CMAGIC))
      SET_ERROR_RETURN(ERR_WRONG_DATABASE);

   FindNextChunk3ds(db->topchunk->children, KFDATA, &kfdata);
   if (kfdata != NULL)
   {
      GetViewportEntry3ds(kfdata, vp);
      ON_ERROR_RETURN;
   } else {
      FindChunk3ds(db->topchunk->children, MDATA, &kfdata);
      if (kfdata != NULL)
      {
	 GetViewportEntry3ds(kfdata, vp);
	 ON_ERROR_RETURN;
      }
   }
}


void PutViewport3ds(database3ds *db, viewport3ds *vp)
{
   chunk3ds *mdata, *kfdata;

   if ((db == NULL) || (vp == NULL)) SET_ERROR_RETURN(ERR_INVALID_ARG);
   if (db->topchunk == NULL) SET_ERROR_RETURN(ERR_INVALID_DATABASE);
   if ((db->topchunk->tag != M3DMAGIC) && (db->topchunk->tag != CMAGIC)) SET_ERROR_RETURN(ERR_WRONG_DATABASE);

   /* Find or create the mdata section */
   FindNextChunk3ds(db->topchunk->children, MDATA, &mdata);
   if (mdata == NULL)
   {
      InitChunkAs3ds(&mdata, MDATA);
      ON_ERROR_RETURN;

      AddChildOrdered3ds(db->topchunk, mdata);
   }

   PutViewportEntry3ds(mdata, vp);
   ON_ERROR_RETURN;
   
   PutDefaultView3ds(mdata, vp);
   ON_ERROR_RETURN;
   

   /* Find or create the kfdata section */
   FindNextChunk3ds(db->topchunk->children, KFDATA, &kfdata);
   if (kfdata == NULL)
   {
      InitChunkAs3ds(&kfdata, KFDATA);
      ON_ERROR_RETURN;

      AddChildOrdered3ds(db->topchunk, kfdata);
   }

   PutViewportEntry3ds(kfdata, vp);
   ON_ERROR_RETURN;
}

void CopyViewport3ds(database3ds *destdb, database3ds *srcdb)
{
   chunk3ds *smdata, *skfdata, *dmdata, *dkfdata, *svp, *dvp;

   if ((destdb == NULL) || (srcdb == NULL)) SET_ERROR_RETURN(ERR_INVALID_ARG);
   if ((srcdb->topchunk == NULL) || (destdb->topchunk == NULL)) SET_ERROR_RETURN(ERR_INVALID_DATABASE);
   if ((srcdb->topchunk->tag != M3DMAGIC) && (srcdb->topchunk->tag != CMAGIC)) SET_ERROR_RETURN(ERR_WRONG_DATABASE);
   if ((destdb->topchunk->tag != M3DMAGIC) && (destdb->topchunk->tag != CMAGIC)) SET_ERROR_RETURN(ERR_WRONG_DATABASE);

   /* Find or make the mdata and kfdata sections in the destination */
   FindNextChunk3ds(destdb->topchunk->children, MDATA, &dmdata);
   if (dmdata == NULL)
   {
      InitChunkAs3ds(&dmdata, MDATA);
      ON_ERROR_RETURN;

      AddChildOrdered3ds(destdb->topchunk, dmdata);
   }

   FindNextChunk3ds(destdb->topchunk->children, KFDATA, &dkfdata);
   if (dkfdata == NULL)
   {
      InitChunkAs3ds(&dkfdata, KFDATA);
      ON_ERROR_RETURN;

      AddChildOrdered3ds(destdb->topchunk, dkfdata);
   }

   /* Find the mdata viewport in the source file */
   FindNextChunk3ds(srcdb->topchunk->children, MDATA, &smdata);
   if (smdata != NULL)
   {
      /* Find the source viewport */
      FindNextChunk3ds(smdata->children, VIEWPORT_LAYOUT, &svp);
      if (svp != NULL)
      {
	 /* Find the viewport chunks (if any) in the destination and delete them */
	 FindNextChunk3ds(dmdata->children, VIEWPORT_LAYOUT, &dvp);
	 if (dvp != NULL) DeleteChunk3ds(dvp);

	 /* Copy the chunk */
	 CopyChunk3ds(svp, &dvp);
	 ON_ERROR_RETURN;

	 AddChildOrdered3ds(dmdata, dvp);
      }

      FindNextChunk3ds(smdata->children, DEFAULT_VIEW, &svp);
      if (svp != NULL)
      {
	 FindNextChunk3ds(dmdata->children, DEFAULT_VIEW, &dvp);
	 if (dvp != NULL) DeleteChunk3ds(dvp);

	 CopyChunk3ds(svp, &dvp);
	 ON_ERROR_RETURN;

	 AddChildOrdered3ds(dmdata, dvp);
      }
      
   }
   
   /* Find the kfdata viewport in the source file */
   FindNextChunk3ds(srcdb->topchunk->children, KFDATA, &skfdata);
   if (skfdata != NULL)
   {
      FindNextChunk3ds(skfdata->children, VIEWPORT_LAYOUT, &svp);
      if (svp != NULL)
      {
	 /* Find the viewport chunks (if any) in the destination and delete them */
	 FindNextChunk3ds(dkfdata->children, VIEWPORT_LAYOUT, &dvp);
	 if (dvp != NULL) DeleteChunk3ds(dvp);

	 /* Copy the chunk */
	 CopyChunk3ds(svp, &dvp);
	 ON_ERROR_RETURN;

	 AddChildOrdered3ds(dkfdata, dvp);
      }
   }
}  
	 
